
#include <clinux/kernel.h>
#include <clinux/sched.h>
#include <clinux/mm.h>
#include <cos/protect.h>

// error_code的格式:
// 	0 ~  0	EX		当程序的外部事件引起的异常时置1
// 	1 ~  1	I		目标描述符在IDT中时, 置1
// 	2 ~  2	TI		在GDT中时置0, 在LDT中时置1
// 	3 ~ 15	SELECTOR INDEX	段选择子索引号
//     16 ~ 31	UNDEFINED

void do_unknown_int(long *esp, long error_code)
{
	panic("unknown interupt occured!\n");
}
void do_divide_error(long *esp, long error_code)
{
	panic("divide_error occured: the divide-error fault ocurs during a DIV or an IDIV instruction when the divisior is zero\n\r");
}
void do_debug(long *esp, long error_code)
{
//	xycprintk(0,0, TEXT_BLINK|TEXT_BK_B|TEXT_FR_I|TEXT_FR_R,
//			"pid:%d, debug occured!", current_task->pid);
	panic("debug occured: the processor triggers this interrupt for any of a number of conditions, refer to 80386 programmer's manual\n\r");
}

void do_nmi(long *esp, long error_code)
{
	panic("nmi occured: while an NMI handler is executing, the processor ignores further interrupt signals at the NMI pin until the next IRET instruction is executed! \n\r");
}

void do_breakpoint(long *esp, long error_code)
{
	panic("breakpoint occured: the saved CS:EIP value points to the byte following the breakpoint\n\r");
}
void do_overflow(long *esp, long error_code)
{
	panic("overflow occured: this trap occurs when the processor encounters an INTO instruction and the OF flag is set.\n\r");
}
void do_bounds_check(long *esp, long error_code)
{
	panic("bounds_check occured: this fault occurs when the processor, while executing a BOUND instruction, finds that the operand exceeds the specified limits.\n\r");
}
void do_invalid_opcode(long *esp, long error_code)
{
	panic("invalid_opcode occured: this fault occurs when an invalid opcode is detected by the execution unit. this exception also occurs when the type of operand is invalid for the given opcode.\n\r");
}
void do_device_not_available(long *esp, long error_code)
{
	panic("device_not_available occured: \n\r1.The processor encounters an ESC instruction, and the EM bit of CR0 is set.\n\r2.The processor encounters either the WAIT instruction or an ESC instruction, and both the MP and TS bits of CR0 are set.\n\r");
}
void do_double_fault(long *esp, long error_code)
{
	panic("double_fault occured: refer to 80386 programmer's manual page 165\n\r");
}
void do_coprocessor_segment_overrun(long *esp, long error_code)
{
	panic("coprocessor_segment_overrun occured");
}
void do_invalid_tss(long *esp, long error_code)
{
	panic("invalid_tss occured\n");
}
void do_segment_not_present(long *esp, long error_code)
{
	panic("segment_not_present occured\n");
}
void do_stack_segment(long *esp, long error_code)
{
	cprintk(TEXT_BLINK|TEXT_BK_B|TEXT_FR_I|TEXT_FR_R, 
			"[trap] error_code = 0x%x,\n\r"
			"[trap] cs:eip = 0x%p : 0x%p,\n\r"
			"[trap] ss:esp = 0x%p : 0x%p,\n\r"
			, error_code, esp[1],esp[0],esp[4],esp[3]);
	panic("stack_segment occured\n");
}
void do_general_protection(long *esp, long error_code)
{
	xycprintk(0,0,TEXT_BLINK|TEXT_BK_B|TEXT_FR_I|TEXT_FR_R, 
			"[trap] error_code = 0x%x,\n\r"
			"[trap] cs:eip = 0x%p : 0x%p,\n\r"
			"[trap] ss:esp = 0x%p : 0x%p,\n\r"
			"[trap] eax = 0x%p,\n\r"
			, error_code, esp[1],esp[0],esp[4],esp[3], esp[-1]);
	panic("general_protection occured\n");
}
void do_page_fault(long *esp, long error_code)
{
	if(!mm_do_page_fault(error_code & 0x00000007, get_cr2())) return;
	xycprintk(0,0,TEXT_BLINK|TEXT_BK_B|TEXT_FR_I|TEXT_FR_R, 
			"[trap] page_fault occured!\n\r"
			"[trap] error_code = 0x%x\n\r"
			"[trap] cs:eip = 0x%p : 0x%p\n\r"
			"[trap] ss:esp = 0x%p : 0x%p\n\r"
			"[trap] eax = 0x%p\n\r"
			, error_code, esp[1],esp[0],esp[4],esp[3], esp[-1]);
	panic("page_fault occured\n\r");
}
void do_reserved(long *esp, long error_code)
{
	panic("reserved occured\n");
}
void do_coprocessor_error(long *esp, long error_code)
{
	panic("coprocessor_error occured!\n");
}

void do_exception(struct kstack_struct * kstack,
		int exception_nr, long error_code)
{
	long * esp = (long *)(&(kstack->eip));
	procs.run_proc->reenter ++;
	switch(exception_nr){
		case 0:
			do_divide_error(esp, error_code);
			break;
		case 1:
			do_debug(esp, error_code);
			break;
		case 2:
			do_nmi(esp, error_code);
			break;
		case 3:
			do_breakpoint(esp, error_code);
			break;
		case 4:
			do_overflow(esp, error_code);
			break;
		case 5:
			do_bounds_check(esp, error_code);
			break;
		case 6:
			do_invalid_opcode(esp, error_code);
			break;
		case 7:
			do_device_not_available(esp, error_code);
			break;
		case 8:
			do_double_fault(esp, error_code);
			break;
		case 9:
			do_coprocessor_segment_overrun(esp, error_code);
			break;
		case 10:
			do_invalid_tss(esp, error_code);
			break;
		case 11:
			do_segment_not_present(esp, error_code);
			break;
		case 12:
			do_stack_segment(esp, error_code);
			break;
		case 13:
			do_general_protection(esp, error_code);
			break;
		case 14:
			do_page_fault(esp, error_code);
			break;
		case 15:
			do_reserved(esp, error_code);
			break;
		case 16:
			do_coprocessor_error(esp, error_code);
			break;
		default:
			do_unknown_int(esp, error_code);
			;
			
	}
	procs.run_proc->reenter --;
	return;
}
